/**
 * 项目名：化工企业安全生产信息化管理平台
 * 日期：    2020-03-17 14:00:30
 * Copyright (c) 2015- -版权所有
 */

package com.joysuch.wwyt.edu.service.impl;

import cn.zlg.common.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.bp.entity.contractor.BpContractor;
import com.joysuch.wwyt.bp.entity.contractor.BpContractorStaff;
import com.joysuch.wwyt.bp.enums.CommonIndexNotiyfyTypes;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.bp.repository.BpJobDao;
import com.joysuch.wwyt.bp.service.BpContractorService;
import com.joysuch.wwyt.bp.service.BpContractorStaffService;
import com.joysuch.wwyt.common.cache.NotifyCache;
import com.joysuch.wwyt.common.entity.CommonIndexNotify;
import com.joysuch.wwyt.common.enums.CommonIndexNotifyTypes;
import com.joysuch.wwyt.common.repository.CommonIndexNotifyDao;
import com.joysuch.wwyt.core.bean.BaseAttachmentBean;
import com.joysuch.wwyt.core.bean.BatchUploadInfoBean;
import com.joysuch.wwyt.core.bean.BatchUploadResult;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.common.util.DateTimeUtil;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.PageDataUtils.PageDataConvert;
import com.joysuch.wwyt.core.exception.BusinessRestrictionsException;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BaseAttachmentRepositoryService;
import com.joysuch.wwyt.core.service.ZipProcessService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.edu.bean.EduCertIdNameDto;
import com.joysuch.wwyt.edu.bean.EduCertUserDto;
import com.joysuch.wwyt.edu.bean.EduCertUserInfoDto;
import com.joysuch.wwyt.edu.bean.EduCertUserQueryBean;
import com.joysuch.wwyt.edu.bean.EduCertificateUserDetailBean;
import com.joysuch.wwyt.edu.bean.EduCertificateUserEditBean;
import com.joysuch.wwyt.edu.bean.EduCertificateUserListBean;
import com.joysuch.wwyt.edu.bean.EduCertificateUserListBean.SearchEduCertificateUser;
import com.joysuch.wwyt.edu.entity.EduCertificate;
import com.joysuch.wwyt.edu.entity.EduCertificateUser;
import com.joysuch.wwyt.edu.entity.dsl.QEduCertificate;
import com.joysuch.wwyt.edu.entity.dsl.QEduCertificateUser;
import com.joysuch.wwyt.edu.enums.CertificateRemindTypes;
import com.joysuch.wwyt.edu.enums.CertificateTypes;
import com.joysuch.wwyt.edu.repository.EduCertificateDao;
import com.joysuch.wwyt.edu.repository.EduCertificateUserDao;
import com.joysuch.wwyt.edu.repository.EduTrainningRecordUserDao;
import com.joysuch.wwyt.edu.service.EduCertificateUserService;
import com.joysuch.wwyt.util.PageableUtil;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.transaction.Transactional;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class EduCertificateUserServiceImpl implements EduCertificateUserService {

    @Autowired
    private EduCertificateUserDao dao;
    @Autowired
    private EduCertificateDao eduCertificateDao;
    @Autowired
    private EduTrainningRecordUserDao eduTrainningRecordUserDao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpDepartDao bpUDepartDao;
    @Autowired
    private BpJobDao bpJobDao;
    @Autowired
    private CommonIndexNotifyDao commonIndexNotifyDao;
    @Autowired
    private EntityManager entityManager;
    @Autowired
    private BpContractorStaffService bpContractorStaffService;
    @Autowired
    private BpContractorService bpContractorService;
    @Autowired
    private BaseAttachmentRepositoryService attachmentRepositoryService;
    @Autowired
    private ZipProcessService zipProcessService;
    @Autowired
    private JPAQueryFactory jpaQueryFactory;

    @Override
    public EduCertificateUser add(EduCertificateUserEditBean entity) {
        List<EduCertificateUser> eList = dao.findByUserIdAndCertIdAndUserContractorFlag(entity.getUserId(),
                entity.getCertId(), entity.getUserContractorFlag());
        if (!org.springframework.util.CollectionUtils.isEmpty(eList)) {
            throw new IllegalArgumentException("该人员已拥有该证书");
        }
        EduCertificateUser content = new EduCertificateUser();
        EduCertificate eduCertificate = eduCertificateDao.findById(entity.getCertId())
                .orElseThrow(() -> new IllegalArgumentException("证书不存在"));
        BeanUtils.copyProperties(entity, content, "id");
        // 计算过期日期
        calExpireTime(eduCertificate, content);
        setCertStatus(content);
        if (!org.springframework.util.CollectionUtils.isEmpty(entity.getAttachmentBeans())) {
            List<BaseAttachmentBean> atList = entity.getAttachmentBeans();
            List<Long> idList = new ArrayList<>();
            for (BaseAttachmentBean atBean : atList) {
                idList.add(atBean.getId());
            }
            content.setAttachmentIdJson(JSON.toJSONString(idList));
        }
        EduCertificateUser save = dao.save(content);
        // 添加提醒任务
        if (CertificateTypes.LIMITED_MONTHS.is(eduCertificate.getEffectiveType())
                && eduCertificate.getExpireRemindOrNot() == 1) {
            addRemindTask(save, eduCertificate);
        }
        return save;
    }

    /**
     * 设置证书状态: 有效; 已过期
     *
     * @param entity
     */
    @Override
    public void setCertStatus(EduCertificateUser entity) {
        Date outOfDateTime = entity.getOutOfDateTime();
        if (outOfDateTime == null) {
            entity.setCertStatus("有效");
            return;
        }
        LocalDate localDate = DateTimeUtil.date2LocalDate(outOfDateTime);
        boolean after = LocalDate.now().isAfter(localDate);
        if (after) {
            entity.setCertStatus("已过期");
        } else {
            entity.setCertStatus("有效");
        }
    }

    private void addRemindTask(EduCertificateUser eduCertificateUser, EduCertificate eduCertificate) {
        String remindUserIdsJson = eduCertificate.getRemindUserIdsJson();
        Long departId = eduCertificate.getDepartId();
        List<Long> list = Lists.newArrayList();
        if (remindUserIdsJson != null) {
            List<Long> userList = JSON.parseArray(remindUserIdsJson, Long.class);
            list.addAll(userList);
        }
        if (departId != null) {
            List<Long> userIdList = baseUserDao.findIdByDepartId(departId);
            list.addAll(userIdList);
        }
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        Long targetUserId = eduCertificateUser.getUserId();
        Integer userContractorFlag = eduCertificateUser.getUserContractorFlag();
        userContractorFlag = userContractorFlag == null ? 0 : userContractorFlag;
        String userName;
        if (userContractorFlag == 0) {
            userName = baseUserDao.getRealNameById(targetUserId);
        } else {
            userName = bpContractorStaffService.getNameById(targetUserId);
        }
        // 计算提醒日期
        LocalTime remindTime = eduCertificate.getRemindTime();
        Integer hours = CertificateRemindTypes.getHours(eduCertificate.getRemindType());
        Date outOfDateTime = eduCertificateUser.getOutOfDateTime();
        LocalDateTime remindDateTime = DateTimeUtil.date2LocalDateTime(outOfDateTime).minusHours(hours);
        remindDateTime = LocalDateTime.of(remindDateTime.toLocalDate(), remindTime);
        LocalDate remindDate = remindDateTime.toLocalDate();
        Long userTableId = eduCertificateUser.getId();
        for (Long userId : list) {
            CommonIndexNotify notify = new CommonIndexNotify();
            notify.setType(CommonIndexNotifyTypes.CERT.getType());
            notify.setReadFlag(0);
            notify.setQueueOrNot(0);
            notify.setRemindedOrNot(0);
            notify.setEduCertUserId(userTableId);
            notify.setRemindDate(remindDate);
            notify.setRemindDateTime(remindDateTime);
            notify.setUserId(userId);
            // 提醒message格式：人+证书+日期+即将过期
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM月dd日");
            String date = simpleDateFormat.format(outOfDateTime);
            String Message = userName + eduCertificate.getName() + date + "即将过期";
            notify.setNotifyMessage(Message);
            commonIndexNotifyDao.save(notify);
        }
    }

    @Override
    public void update(EduCertificateUserEditBean entity) {
        EduCertificateUser content = dao.findById(entity.getId()).get();
        EduCertificate eduCertificate = eduCertificateDao.findById(content.getCertId()).get();
        BeanUtils.copyProperties(entity, content, "id");
        List<BaseAttachmentBean> atList = entity.getAttachmentBeans();
        if (atList == null) {
            atList = Lists.newArrayList();
        }
        List<Long> idList = new ArrayList<>();
        for (BaseAttachmentBean atBean : atList) {
            idList.add(atBean.getId());
        }
        content.setAttachmentIdJson(JSON.toJSONString(idList));
        setCertStatus(content);
        EduCertificateUser save = dao.save(content);
        List<EduCertificateUser> eList = dao.findByUserIdAndCertIdAndUserContractorFlag(entity.getUserId(),
                entity.getCertId(), entity.getUserContractorFlag());
        if (eList.size() > 1) {
            throw new IllegalArgumentException("该人员已拥有该证书");
        }
        // 修改时 任务和到期日期的修改 暂时不做复杂修改
        Integer expireRemindOrNot = eduCertificate.getExpireRemindOrNot();
        if (expireRemindOrNot != null && expireRemindOrNot == 0) {
            return;
        }
        Integer hours = CertificateRemindTypes.getHours(eduCertificate.getRemindType());
        Date outOfDateTime = content.getOutOfDateTime();
        LocalDateTime remindDateTime = DateTimeUtil.date2LocalDateTime(outOfDateTime).minusHours(hours);
        LocalDate remindDate = remindDateTime.toLocalDate();
        Long userTableId = content.getId();
        Long userId = content.getUserId();
        CommonIndexNotify notify = commonIndexNotifyDao.findFirstByEduCertUserIdAndUserIdAndType(userTableId, userId,
                CommonIndexNotiyfyTypes.CERT.getType());
        if (notify != null) {
            notify.setRemindDate(remindDate);
            notify.setRemindDateTime(remindDateTime);
            notify.setUserId(userId);
            // 提醒message格式：人+证书+日期+即将过期
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM月dd日");
            String date = simpleDateFormat.format(outOfDateTime);
            String Message = baseUserDao.getRealNameById(userId) + eduCertificate.getName() + date + "即将过期";
            notify.setNotifyMessage(Message);
            commonIndexNotifyDao.save(notify);
        }
    }

    private void calExpireTime(EduCertificate eduCertificate, EduCertificateUser content) {
        if (CertificateTypes.LIMITED_MONTHS.is(eduCertificate.getEffectiveType())) {
            Integer month = eduCertificate.getEffectiveDurationMonth();
            Date takenTime = content.getTakenTime();
            LocalDate localDate = DateTimeUtil.date2LocalDateTime(takenTime).toLocalDate().plusMonths(month);
            content.setOutOfDateTime(
                    DateTimeUtil.localDateTime2Date(LocalDateTime.of(localDate, LocalTime.of(0, 0, 0))));
        }
    }

    @Override
    public Page<EduCertificateUserListBean> findByPage(Pageable page, SearchEduCertificateUser condition) {
        // 旧数据填补证书状态信息
        List<EduCertificateUser> list = dao.findByCertStatusIsNull();
        if (!org.springframework.util.CollectionUtils.isEmpty(list)) {
            for (EduCertificateUser certificateUser : list) {
                setCertStatus(certificateUser);
            }
            dao.saveAll(list);
        }

        Predicate predicate = prepareListSearchCondition(condition);

        Page<EduCertificateUser> data = predicate == null ? dao.findAll(page) : dao.findAll(predicate, page);

        return PageDataUtils.convertPageData(data,
                new PageDataConvert<EduCertificateUserListBean, EduCertificateUser>() {

                    @Override
                    public EduCertificateUserListBean convert(EduCertificateUser f) {
                        EduCertificateUserListBean bean = new EduCertificateUserListBean();
                        BeanUtils.copyProperties(f, bean);
                        bean.setRefUrl(f.getRefUrl());
                        Integer userContractorFlag = f.getUserContractorFlag();
                        Long userId = f.getUserId();
                        if (userContractorFlag == null || userContractorFlag == 0) {
                            baseUserDao.findById(userId).ifPresent(user -> {
                                bean.setUserName(user.getRealName());
                                // bean.setCompany(user.getWorkCompanyId());
                                bean.setDepartName(bpUDepartDao.findDepartNameById(user.getDepartId()));
                                bean.setJobName(bpJobDao.getNameById(user.getJob()));
                                bean.setSex(user.getGender());
                                bean.setCompany(Context.getCompanyName());
                            });
                        } else {
                            BpContractorStaff staff = bpContractorStaffService.getById(userId);
                            if (staff != null) {
                                bean.setUserName(staff.getName());
                                bean.setSex(staff.getGender());
                                Long contractorId = staff.getContractorId();
                                BpContractor bpContractor = bpContractorService.get(contractorId);
                                if (bpContractor != null) {
                                    bean.setCompany(bpContractor.getCompanyName());
                                }
                            }
                        }

                        eduCertificateDao.findById(f.getCertId()).ifPresent(cert -> {
                            bean.setCertName(cert.getName());
                            bean.setEffectiveTypeName(CertificateTypes.findNameByCode(cert.getEffectiveType()));
                        });
                        return bean;
                    }

                });
    }

    private Predicate prepareListSearchCondition(SearchEduCertificateUser condition) {
        Predicate p = null;
        QEduCertificateUser q = QEduCertificateUser.eduCertificateUser;
        if (condition.getCertId() != null) {
            p = ExpressionUtils.and(p, q.certId.eq(condition.getCertId()));
        }
        if (condition.getUserName() != null) {
            List<Long> list = baseUserDao.getUserIdByNameContains(condition.getUserName());
            List<Long> staffIdList = bpContractorStaffService.getStaffIdByNameContains(condition.getUserName());
            list.addAll(staffIdList);
            p = ExpressionUtils.and(p, q.userId.in(list));
        }
        if (condition.getCertStatus() != null) {
            p = ExpressionUtils.and(p, q.certStatus.eq(condition.getCertStatus()));
        }
        return p;
    }

    @Override
    public void delete(Long id) throws BusinessRestrictionsException {
        // 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用。不能删除时将抛出业务异常
        EduCertificateUser eduCertificateUser = dao.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("操作失败"));
        checkBussinessRestrictions(id);
        dao.deleteById(id);
        eduTrainningRecordUserDao.setCertUserIdToNull(id);
        // 证书删除，去除到期提醒
        EduCertificate eduCertificate = eduCertificateDao.findById(eduCertificateUser.getCertId())
                .orElseThrow(() -> new IllegalArgumentException("证书不存在"));
        if (CertificateTypes.LIMITED_MONTHS.is(eduCertificate.getEffectiveType())
                && eduCertificate.getExpireRemindOrNot() == 1) {
            removeRemindTask(eduCertificateUser);
        }
    }

    // 移除缓存队列，删除数据表数据
    private void removeRemindTask(EduCertificateUser eduCertificateUser) {
        Long userTableId = eduCertificateUser.getId();
        List<CommonIndexNotify> notifyList = commonIndexNotifyDao.findByEduCertUserId(userTableId);
        for (CommonIndexNotify notify : notifyList) {
            // 已经加入队列删除
            if (notify.getQueueOrNot() == 1) {
                NotifyCache.cancelFuture(getMapKey(notify));
            }
            commonIndexNotifyDao.deleteById(notify.getId());
        }
    }

    // map
    private String getMapKey(CommonIndexNotify notify) {
        return notify.getTenentId() + ":" + notify.getOrgCode().substring(0, 7) + ":" + notify.getUserId() + ":"
                + CommonIndexNotifyTypes.CERT + ":" + notify.getId();
    }

    /**
     * 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用
     *
     * @param id
     *               要删除的业务ID
     */
    private void checkBussinessRestrictions(Long id) throws BusinessRestrictionsException {

    }

    @Override
    public EduCertificateUser findById(Long id) {
        return dao.findById(id).orElse(null);
    }

    @Override
    public ResultBean certPage(EduCertUserQueryBean bean, Pageable pageable) {
        Integer userContractorFlag = bean.getUserContractorFlag();
        userContractorFlag = userContractorFlag == null ? 0 : userContractorFlag;
        if (userContractorFlag == 0) {
            return getEduUserCert(bean, pageable);
        } else {
            return getEduContractorUserCert(bean, pageable);
        }

    }

    private ResultBean getEduContractorUserCert(EduCertUserQueryBean bean, Pageable pageable) {
        return bpContractorStaffService.getEduContractorUserCert(bean, pageable);
    }

    private ResultBean getEduUserCert(EduCertUserQueryBean bean, Pageable pageable) {
        // 所有人,不管有没有证书
        StringBuilder stringBuilder = new StringBuilder(
                "select bu.code code,bu.real_name userName,bd.id departId,bd.name departName,bei.name enterPriseName ,bu.id userId "
                        + ",bj.name jobName from wwyt_base_user bu left join wwyt_bp_depart bd on bd.id=bu.depart_id inner join wwyt_bp_enterprise_info bei on"
                        + " bei.id=bu.work_company_id inner join wwyt_bp_job bj on bj.id=bu.job where bu.delete_flag=\'0\' and bd.delete_flag=\'0\' and (bu.state is null or bu.state !=44)"
                        + " and bj.delete_flag=\'0\' ");
        String name = bean.getName();
        String enterPrise = bean.getEnterPrise();
        Long departId = bean.getDepartId();
        // Long certId = bean.getCertId();
        if (name != null) {
            stringBuilder.append(" and (bu.code like \'%" + name + "%\' or bu.real_name like \'%" + name + "%\')");
        }
        if (departId != null) {
            stringBuilder.append(" and bd.id = \'" + departId + "\'");
        }
        if (enterPrise != null) {
            stringBuilder.append(" and bei.name = \'" + enterPrise + "\'");
        }
        stringBuilder.append(" order by bu.id desc");
        log.info("所有人员证书查询sql:{}", stringBuilder.toString());
        Query nativeQuery = entityManager.createNativeQuery(stringBuilder.toString());
        nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(EduCertUserDto.class));
        List<EduCertUserDto> resultList = nativeQuery.getResultList();
        Iterator<EduCertUserDto> userDtoIterator = resultList.iterator();
        while (userDtoIterator.hasNext()) {
            EduCertUserDto eduCertUserDto = userDtoIterator.next();
            // 去除过期证书
            LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now(), LocalTime.of(0, 0, 0));
            Date date = DateTimeUtil.localDateTime2Date(localDateTime);
            List<EduCertificate> eduCertificateList = eduCertificateDao
                    .getCertByUserId(eduCertUserDto.getUserId().longValue(), 0, date);
            List<EduCertIdNameDto> tempList = null;
            // 一人多证
            Map<Long, Boolean> map = new ConcurrentHashMap<>();
            List<EduCertificate> collect = eduCertificateList.stream().filter(distinctById(r -> r.getId(), map))
                    .collect(Collectors.toList());
            if (!org.springframework.util.CollectionUtils.isEmpty(bean.getCertIdList())) {
                if (bean.getTypeFlag() != null && bean.getTypeFlag() == 1) {
                    // 交集
                    List<Long> certIdList = collect.stream().map(r -> r.getId()).collect(Collectors.toList());
                    if (!certIdList.containsAll(bean.getCertIdList())) {
                        userDtoIterator.remove();
                    }
                    tempList = collect.stream().map(EduCertIdNameDto::new).collect(Collectors.toList());
                } else {
                    // 并集
                    // 1 可以加入
                    int flag = 1;
                    int sum = 0;
                    Iterator<EduCertificate> iterator = collect.iterator();
                    while (iterator.hasNext()) {
                        EduCertificate next = iterator.next();
                        if (bean.getCertIdList().contains(next.getId())) {
                            sum++;
                        } else {
                            iterator.remove();
                        }
                    }
                    if (sum == 0) {
                        userDtoIterator.remove();
                        flag = 0;
                    }
                    if (flag == 1) {
                        tempList = collect.stream().map(EduCertIdNameDto::new).collect(Collectors.toList());
                    }
                }
            } else {
                tempList = collect.stream().map(EduCertIdNameDto::new).collect(Collectors.toList());
            }
            eduCertUserDto.setDtoList(tempList);
        }
        return getResultBean(pageable, resultList);
    }

    @Override
    public ResultBean userInfoCert(Pageable pageable, Long userId, Integer userContractorFlag) {
        userContractorFlag = userContractorFlag == null ? 0 : userContractorFlag;
        Page<EduCertUserInfoDto> dtoList = dao.userInfoCert(userId, pageable, userContractorFlag);
        for (EduCertUserInfoDto dto : dtoList) {
            Date expireTime = dto.getExpireTime();
            if (expireTime == null) {
                dto.setState("有效");
                continue;
            }
            if (LocalDate.now().isAfter(DateTimeUtil.date2LocalDateTime(dto.getExpireTime()).toLocalDate())) {
                dto.setState("过期");
            } else {
                dto.setState("有效");
            }
        }
        return ResultBean.pageData(dtoList.getContent(), dtoList.getTotalElements());
    }

    private ResultBean getResultBean(Pageable pageable, List<EduCertUserDto> dtoList) {
        List<EduCertUserDto> list = PageableUtil.getList(pageable, dtoList);
        return ResultBean.pageData(list, dtoList.size());
    }

    static <T> java.util.function.Predicate<T> distinctById(Function<? super T, ?> function, Map map) {
        return t -> map.putIfAbsent(function.apply(t), Boolean.TRUE) == null;
    }

    @Override
    public EduCertificateUserDetailBean getById(Long id) {
        EduCertificateUser entity = findById(id);
        if (entity == null) {
            return null;
        }
        EduCertificateUserDetailBean bean = new EduCertificateUserDetailBean();
        BeanUtils.copyProperties(entity, bean);
        bean.setCertName(eduCertificateDao.getNameById(entity.getCertId()));
        bean.setUserName(baseUserDao.getRealNameById(entity.getUserId()));
        Integer userContractorFlag = entity.getUserContractorFlag();
        Long userId = bean.getUserId();
        if (userContractorFlag == null || userContractorFlag == 0) {
            baseUserDao.findById(userId).ifPresent(user -> {
                bean.setUserName(user.getRealName());
                bean.setDepartName(bpUDepartDao.findDepartNameById(user.getDepartId()));
                bean.setJobName(bpJobDao.getNameById(user.getJob()));
                bean.setSex(user.getGender());
                bean.setCompany(Context.getCompanyName());
            });
        } else {
            BpContractorStaff staff = bpContractorStaffService.getById(userId);
            if (staff != null) {
                bean.setUserName(staff.getName());
                bean.setSex(staff.getGender());
                Long contractorId = staff.getContractorId();
                if (contractorId != null) {
                    BpContractor bpContractor = bpContractorService.get(contractorId);
                    bean.setCompany(bpContractor == null ? null : bpContractor.getCompanyName());
                }
            }
        }
        eduCertificateDao.findById(entity.getCertId()).ifPresent(cert -> {
            bean.setCertName(cert.getName());
            bean.setEffectiveType(cert.getEffectiveType());
            bean.setEffectiveTypeName(CertificateTypes.findNameByCode(cert.getEffectiveType()));
        });
        bean.setUserContractorFlag(userContractorFlag);
        if (StringUtils.isNotBlank(entity.getAttachmentIdJson())) {
            List<Long> idList = JSON.parseArray(entity.getAttachmentIdJson(), Long.class);
            List<BaseAttachmentBean> attachmentBeans = new ArrayList<>();
            for (Long atId : idList) {
                BaseAttachmentBean atBean = attachmentRepositoryService.findByIdIntoBean(atId);
                attachmentBeans.add(atBean);
            }
            bean.setAttachmentBeans(attachmentBeans);
        }
        return bean;
    }

    @Override
    public BatchUploadResult batchUploadImages(MultipartFile file) {
        BatchUploadResult result = new BatchUploadResult();
        List<BatchUploadInfoBean> list = unzipAndParseUploadInfo(file,"UTF-8", "GBK");
        list.forEach( f -> {
            if(f.isIgnored()) {
                result.getIgnoreItems().add(f.getFilename());
            }
        });
        List<BatchUploadInfoBean> infos = list.stream().filter(f -> !f.isIgnored()).collect(Collectors.toList());
        if (infos.size() > 0) {
            List<String> certNos = infos.stream().map(BatchUploadInfoBean::getBaseName)
                    .collect(Collectors.toList());
            List<Tuple> users = findCertificateUsers(certNos);
            infos.forEach(e -> {
                Optional<EduCertificateUser> first = users.stream()
                        .filter(u -> {
                            String key = u.get(QEduCertificate.eduCertificate).getName()+"+"
                                    +u.get(QEduCertificateUser.eduCertificateUser).getCertNo();
                           return key.equals(e.getBaseName());
                        }).map(u -> u.get(QEduCertificateUser.eduCertificateUser)).findFirst();
                if (first.isPresent()) {
                    first.get().setAttachmentIdJson("[" + e.getId() + "]");
                    dao.save(first.get());
                    result.setSucceedCount(result.getSucceedCount() + 1);
                } else {
                    result.setFailCount(result.getFailCount() + 1);
                    result.getFailItems().add(e.getFilename());
                }
            });
            // 清理临时目录
            zipProcessService.deleteTempDir(infos.get(0).getTempDir());
        }
        return result;
    }

    List<Tuple> findCertificateUsers(List<String> certNames) {
        List<Predicate> list = new ArrayList<>(certNames.size());
        QEduCertificate c = QEduCertificate.eduCertificate;
        QEduCertificateUser u = QEduCertificateUser.eduCertificateUser;
        Predicate p = null;

        for(String s : certNames) {
            String[] ss = s.split("\\+");
            if(ss.length == 2) {
                p = ExpressionUtils.or(p, c.name.eq(ss[0]).and(u.certNo.eq(ss[1])));
            }
        }
        if(p == null) {
            return Collections.EMPTY_LIST;
        }
        return jpaQueryFactory.select(u,c).from(c,u).where(u.certId.eq(c.id), p).fetch();
    }

    private List<BatchUploadInfoBean> unzipAndParseUploadInfo(MultipartFile file, String...tryEncodings) {
        for(String encoding: tryEncodings) {
            try {
                List<BatchUploadInfoBean> infos = zipProcessService.batchUploadAttachments(file.getInputStream(), true, 1,
                        Charset.forName(encoding), "jpg", "jpeg", "png", "pdf");
                return infos;
            } catch (Exception e) {
                log.error("解析{}出错，encoding={}",file.getOriginalFilename(), encoding,e);
            }
        }
        throw new RuntimeException("解析zip文件异常:file="+file.getOriginalFilename());
    }

}
